package pishen;

import hck.Article;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.ListIterator;

import combine.RankedAuthor;

public class ArticleParser {
	private ArrayList<Article> articleList;
	private HashMap<String, Author> authorMap = new HashMap<String, Author>();
	private ArrayList<Author> authorList = new ArrayList<Author>();
	private HashMap<String, SimpleArticle> mainArticleMap = new HashMap<String, SimpleArticle>();
	private ArrayList<SimpleArticle> mainArticleList = new ArrayList<SimpleArticle>();
	private PageRankGraph graph;
	private ArrayList<RankedAuthor> passerbyRankedList = new ArrayList<RankedAuthor>();
	private HashMap<String, RankedAuthor> passerbyRankedMap = new HashMap<String, RankedAuthor>();

	public static void main(String[] args) {
		ArticleParser ap = new ArticleParser();
		String targetDir = args[0];
		ap.readArticles(new File(targetDir + "article_collection.ser"));
		System.out.println("readArticles finished");
		ap.initializeAuthors();
		System.out.println("initializeAuthors finished");
		ap.fillLinkInfo();
		System.out.println("fillLinkInfo finished");
		ap.createPositiveGraph();
		System.out.println("createNodeList finished");
		ap.writeNodesInfo(new File(targetDir + "positive_graph.ser"));
		System.out.println("writeNodesInfo finished");
		ap.createNegativeGraph();
		System.out.println("createNegativeGraph finished");
		ap.writeNodesInfo(new File(targetDir + "negative_graph.ser"));
		System.out.println("writeNodesInfo finished");
		ap.writePasserbyRankedList(new File(targetDir + "passerby_result.ser"));
		System.out.println("writePasserbyRankedList finished");
		ap.writeAuthorsInfo(new File(targetDir + "author_collection.ser"));
		System.out.println("writeAuthorsInfo finished");
	}

	public void readArticles(File file) {
		try {
			ObjectInputStream in = new ObjectInputStream(new FileInputStream(
					file));
			articleList = (ArrayList<Article>) in.readObject();
			in.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
	}

	public void initializeAuthors() {
		ListIterator<Article> articleIterator = articleList.listIterator();
		while (articleIterator.hasNext()) {
			Article article = articleIterator.next();
			// create a new author if this author didn't exist
			if (!authorMap.containsKey(article.getAuthor())) {
				Author newAuthor = new Author(article.getAuthor());
				authorMap.put(article.getAuthor(), newAuthor);
				authorList.add(newAuthor);
			}
			// add this article to mainArticleMap and the Author's articleList
			SimpleArticle simpleArticle = new SimpleArticle(article.getArticleID(),
					article.getAuthor());
			mainArticleMap.put(simpleArticle.getName(), simpleArticle);
			mainArticleList.add(simpleArticle);
			authorMap.get(simpleArticle.getAuthorName()).addSimpleArticle(simpleArticle.getName());
		}
	}

	public void fillLinkInfo() {
		//create passerbyRankedList, passerbyRankedMap
		ListIterator<Author> authorIterator = authorList.listIterator();
		while(authorIterator.hasNext()){
			Author author = authorIterator.next();
			RankedAuthor rankedAuthor = new RankedAuthor(author.getName(), 0); 
			passerbyRankedList.add(rankedAuthor);
			passerbyRankedMap.put(author.getName(), rankedAuthor);
		}
		//fill link's info
		ListIterator<Article> articleIterator = articleList.listIterator();
		while (articleIterator.hasNext()) {
			Article article = articleIterator.next();
			SimpleArticle simpleArticle = mainArticleMap.get(article.getArticleID());
			//iterate through push
			ListIterator<String> commenterIterator = article.getRecommendersList().listIterator();
			while(commenterIterator.hasNext()){
				String commenterName = commenterIterator.next();
				//find the guy who push this article, add a link from him to this author
				if(authorMap.containsKey(commenterName)){
					authorMap.get(commenterName).addPush(simpleArticle.getName());
				}else{
					// handle non-author push
					RankedAuthor rankedAuthor = passerbyRankedMap.get(simpleArticle.getAuthorName());
					rankedAuthor.setPrestige(rankedAuthor.getPrestige() + 0.3);
				}
			}
			//iterate through arrow
			commenterIterator = article.getNoncommitersList().listIterator();
			while(commenterIterator.hasNext()){
				String commenterName = commenterIterator.next();
				//find the guy who arrow this article, add a link from him to this author
				if(authorMap.containsKey(commenterName)){
					authorMap.get(commenterName).addArrow(simpleArticle.getName());
				}else{
					// handle non-author arrow
					RankedAuthor rankedAuthor = passerbyRankedMap.get(simpleArticle.getAuthorName());
					rankedAuthor.setPrestige(rankedAuthor.getPrestige() + 0.1);
				}
			}
			// iterate through hiss
			commenterIterator = article.getUnrecommendersList().listIterator();
			while(commenterIterator.hasNext()){
				String commenterName = commenterIterator.next();
				//find the guy who hiss this article, add a link from him to this author
				if(authorMap.containsKey(commenterName)){
					authorMap.get(commenterName).addHiss(simpleArticle.getName());
				}else{
					// handle non-author hiss
					RankedAuthor rankedAuthor = passerbyRankedMap.get(simpleArticle.getAuthorName());
					rankedAuthor.setPrestige(rankedAuthor.getPrestige() - 0.2);
				}
			}
		}
	}
	
	public void createPositiveGraph(){
		graph = new PageRankGraph();
		ListIterator<Author> authorIterator = authorList.listIterator();
		//create AuthorNode for each Author
		while(authorIterator.hasNext()){
			Author author = authorIterator.next();
			AuthorNode newAuthorNode = new AuthorNode(author.getName());
			graph.addAuthorNode(newAuthorNode);
		}
		//fill in link information
		authorIterator = authorList.listIterator();
		while(authorIterator.hasNext()){
			Author author = authorIterator.next();
			if(author.getNumOfPush() > 0 || author.getNumOfArrow() > 0){
				AuthorNode authorNode = graph.getAuthorNode(author.getName());
				double weightUnit = 1 / (double)(author.getNumOfPush()*Author.weightOfRecommend + author.getNumOfArrow()*Author.weightOfArrow);
				//check all push links
				for(int i = 0; i < author.getNumOfPush(); i++){
					//add the weight to the combine link
					String targetAuthorName = mainArticleMap.get(author.getPushTarget(i)).getAuthorName();
					authorNode.addLink(targetAuthorName, weightUnit * Author.weightOfRecommend);
				}
				//check all arrow links
				for(int i = 0; i < author.getNumOfArrow(); i++){
					//add the weight to the combine link
					String targetAuthorName = mainArticleMap.get(author.getArrowTarget(i)).getAuthorName();
					authorNode.addLink(targetAuthorName, weightUnit * Author.weightOfArrow);
				}
			}
		}
	}
	
	public void createNegativeGraph(){
		graph = new PageRankGraph();
		ListIterator<Author> authorIterator = authorList.listIterator();
		//create AuthorNode for each Author
		while(authorIterator.hasNext()){
			Author author = authorIterator.next();
			AuthorNode newAuthorNode = new AuthorNode(author.getName());
			graph.addAuthorNode(newAuthorNode);
		}
		//fill in link information
		authorIterator = authorList.listIterator();
		while(authorIterator.hasNext()){
			Author author = authorIterator.next();
			if(author.getNumOfHiss() != 0 && author.getNumOfHiss() != mainArticleMap.size()){
				AuthorNode authorNode = graph.getAuthorNode(author.getName());
				int numOfHiss = author.getNumOfHiss();
				int numOfNoHiss = mainArticleMap.size() - author.getNumOfHiss();
				double hissLinkWeight = (numOfHiss - 1) / (double)(numOfHiss * numOfNoHiss + numOfHiss *(numOfHiss - 1));
				double noHissLinkWeight = 1 / (double)(numOfNoHiss + (numOfHiss - 1));
				//check all hiss link
				for(int i = 0; i < author.getNumOfHiss(); i++){
					String targetAuthorName = mainArticleMap.get(author.getHissTarget(i)).getAuthorName();
					authorNode.addLink(targetAuthorName, hissLinkWeight);
				}
				//check all no-hiss link
				ListIterator<SimpleArticle> simpleArticleIterator = mainArticleList.listIterator();
				while(simpleArticleIterator.hasNext()){
					SimpleArticle simpleArticle = simpleArticleIterator.next();
					if(!author.containsHiss(simpleArticle.getName())){
						authorNode.addLink(simpleArticle.getAuthorName(), noHissLinkWeight);
					}
				}
			}
		}
	}
	
	public void writeNodesInfo(File file){
		try {
			ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(file));
			out.writeObject(graph);
			out.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	public void writePasserbyRankedList(File file){
		try {
			ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(file));
			out.writeObject(passerbyRankedList);
			out.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	public void writeAuthorsInfo(File file){
		ObjectOutputStream out;
		try {
			out = new ObjectOutputStream(new FileOutputStream(file));
			out.writeObject(authorList);
			//out.writeObject(authorMap);
			out.writeObject(mainArticleMap);
			out.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
	}

}
